﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Studio7i.Dominio;
using System.Data.Entity.Infrastructure;
using System.Collections;

namespace Studio7i.Persistencia.EF
{
    public class SalaDAO : ISalaDAO
    {
        public Sala Crear(Sala salaACrear)
        {
            using (EFContext db = new EFContext(ConexionUtil.ObtenerCadena()))
            {
                // Obtenemos el siguiente código (PK)
                int? codigo = db.Salas.Select(l => (int?)l.Codigo).Max();
                salaACrear.Codigo = (codigo ?? 0) + 1;
                // Atachamos al contexto cada objeto anidado (incluyendo los que están en colecciones)
                db.Locales.Attach(salaACrear.Local);
                if (salaACrear.Instrumentos != null)
                    foreach (Instrumento instrumento in salaACrear.Instrumentos)
                        db.Instrumentos.Attach(instrumento);
                // Solicitamos agregar la sala y persistir los cambios en la BD
                db.Salas.Add(salaACrear);
                db.SaveChanges();
            }
            return Obtener(salaACrear.Codigo);
        }
        public Sala Obtener(int codigo)
        {
            using (EFContext db = new EFContext(ConexionUtil.ObtenerCadena()))
            {
                var sala = from l in db.Salas
                               .Include("Local")
                               .Include("Instrumentos")
                            where l.Codigo == codigo
                            select l;
                return sala.SingleOrDefault();
            }
        }
        public Sala Modificar(Sala salaAModificar)
        {
            using (EFContext db = new EFContext(ConexionUtil.ObtenerCadena()))
            {
                // Obtenermos la sala que está en la BD
                Sala sala = (from s in db.Salas
                                 .Include("Local")
                                 .Include("Instrumentos")
                             where s.Codigo == salaAModificar.Codigo
                             select s).Single();
                // Variable que administra el contexto de entidades en memoria
                var contexto = ((IObjectContextAdapter)db).ObjectContext;
                // Aplicamos cambio en objeto anidado Local
                var localKey = contexto.CreateEntityKey("Locales", salaAModificar.Local); // Es como una PK para el local
                object local;
                var encontrado = contexto.TryGetObjectByKey(localKey, out local); // Intentamos obtener el objeto del contexto
                if (!encontrado) // Si aún no está en el contexto hay que agregarlo pero sin cambios para que no haga INSERT del local
                {
                    db.Locales.Attach(salaAModificar.Local);
                    db.Entry(salaAModificar.Local).State = System.Data.EntityState.Unchanged;
                }
                local = contexto.GetObjectByKey(localKey);
                sala.Local = (Local)local;
                // Eliminamos todos los elementos de la relación many-to-many con Instrumentos
                if (sala.Instrumentos != null)
                    foreach (Instrumento i in sala.Instrumentos.ToList())
                        sala.Instrumentos.Remove(db.Instrumentos.Attach(i));
                else
                    sala.Instrumentos = new List<Instrumento>();
                // Agregamos al contexto los objetos "no atachados" que vienen en el objeto de dominio como colección anidada
                if (salaAModificar.Instrumentos != null)
                    foreach (Instrumento instrumento in salaAModificar.Instrumentos)
                    {
                        var entidadKey = contexto.CreateEntityKey("Instrumentos", instrumento); // Es como una PK para el instrumento
                        object entidad;
                        var existe = contexto.TryGetObjectByKey(entidadKey, out entidad); // Intentamos obtener el objeto del contexto
                        if (!existe) // Si aún no está en el contexto hay que agregarlo pero sin cambios para que no haga INSERT del instrumento
                        {
                            db.Instrumentos.Attach(instrumento);
                            db.Entry(instrumento).State = System.Data.EntityState.Unchanged;
                        }
                        entidad = contexto.GetObjectByKey(entidadKey); // Ahora sí con seguridad, obtenemos el instrumento de memoria
                        sala.Instrumentos.Add((Instrumento)entidad); // Agregamos a la colección many-to-many los instrumentos solicitados
                    }
                // Aplicamos los cambios de propiedades escalares al objeto principal de la BD
                db.Entry(sala).CurrentValues.SetValues(salaAModificar);
                // Solicitamos que se envíen los cambios a la BD
                db.SaveChanges();
                // Retornamos la sala con los cambios aplicados
                return sala;
            }
        }
        public void Eliminar(Sala salaAEliminar)
        {
            using (EFContext db = new EFContext(ConexionUtil.ObtenerCadena()))
            {
                Sala salaExistente = (from s in db.Salas
                                 .Include("Local")
                                 .Include("Instrumentos")
                            where s.Codigo == salaAEliminar.Codigo
                            select s).Single();
                db.Salas.Remove(salaExistente);
                db.SaveChanges();
            }
        }

        public ICollection<Sala> ListarTodos()
        {
            using (EFContext db = new EFContext(ConexionUtil.ObtenerCadena()))
            {
                var busqueda = from s in db.Salas
                                    .Include("Local")
                                    .Include("Instrumentos")
                                select s;
                return busqueda.ToList();
            }
        }
        public ICollection<Sala> ListarXBusqueda(int? codigo, string nombre, string caracteristicas, int? capacidad, Local local, string comentarios)
        {
            using (EFContext db = new EFContext(ConexionUtil.ObtenerCadena()))
            {
                var busqueda = from s in db.Salas
                                   .Include("Local")
                                   .Include("Instrumentos")
                                select s;
                if (codigo != null)
                    busqueda = busqueda.Where(s => s.Codigo == codigo);
                if (nombre != null)
                    busqueda = busqueda.Where(s => s.Nombre.Contains(nombre));
                if (caracteristicas != null)
                    busqueda = busqueda.Where(s => s.Caracteristicas.Contains(caracteristicas));
                if (capacidad != null)
                    busqueda = busqueda.Where(s => s.Capacidad == capacidad);
                if (local != null)
                    busqueda = busqueda.Where(s => s.Local == local);
                if (comentarios != null)
                    busqueda = busqueda.Where(s => s.Comentarios.Contains(comentarios));
                return busqueda.ToList();
            }
        }

    }
}